#include "planthread.h"

#include <QDateTime>
#include <QDebug>

#include "data/mycachedata.h"
#include "data/receivedata.h"
#include "data/myfunc.h"

PlanThread::PlanThread(QObject *parent)
    : QThread(parent)
    , running(true)
    , mycdata(MyCacheData::getInstance())
    , m_ReceiveData(ReceiveData::getInstance())
{
    plans = mycdata->getPlans();
    timePlan = this->getSec();
}

PlanThread::~PlanThread()
{
    running=false;
    try{
        this->terminate();
        this->wait();
        qInfo() << "PlanThread::destroy\n";
    }catch(...){
        qDebug() << "PlanThread::destroy fail\n";
    }
}

void PlanThread::run()
{
    qInfo() << QString("PlanThread running,plans.size=%1").arg(plans.size());
    while (running) {
        for (QList<Plan>::iterator it = plans.begin();it!=plans.end();it++)
        {
            switch (it->planAtt.planType)
            {
            case 1:
            {
                if (mapCurTime(it->ptime)
                    && ((timePlan + it->planAtt.planEffect)<this->getSec()))
                {
                    doCmd(it->planCmds);
                }
            }
                break;
            case 2:
            {
                if (mapSleepTime(it->timeVS,it->psleep)
                    && ((timePlan + it->planAtt.planEffect)<this->getSec()))
                {
                    doCmd(it->planCmds);
                }
            }
                break;
            case 3:
            {
                if (conditionJude(it->timeVS,it->plancons)
                    && ((timePlan + it->planAtt.planEffect)<this->getSec()))
                {
                    doCmd(it->planCmds);
                    //printf("conditionJude success!\n");
                }
            }
                break;
            case 4:
            {
                if (!it->pFStart.execFlag
                        && ((timePlan + it->pFStart.waitSec)<this->getSec()))
                    {
                        it->pFStart.execFlag = true;
                        doCmd(it->planCmds);
                    }
                    break;
            }
            default:
                break;
            }
        }
        try{
            qint64 _usec = this->getUsec();
            m_MutexWDS.lock();
            QList<WDSPCS>::iterator it = WriteDataS.begin();
            while (it != WriteDataS.end())
            {
                if (it->sleep < _usec) {
                    //printf("sleep(%ld),usec(%ld)\n", it->sleep, _usec);
                    RDS rds(it->exeType,it->pID,it->pType,it->val);
                    m_ReceiveData->addRDS(rds);
                    qDebug() << QString("plan cmd(%1),time(%2),ip(%3),pID(%4),pType(%5),val(%6)")
                                .arg(it->desc)
                                .arg(PFunc::getCurrentTime())
                                .arg(it->ipInt)
                                .arg(it->pID).arg((int)it->pType).arg(it->val,0,'f',2);
                    it = WriteDataS.erase(it);
                    continue;
                }
                it++;
            }
            m_MutexWDS.unlock();
        }
        catch (...) {
            printf("error for get sleep item WDS and add to ReceiveData \n");
        }
        this->msleep(100);
    }
    exec();
};

qint64 PlanThread::getUsec()
{
    return QDateTime::currentMSecsSinceEpoch();
}

qint64 PlanThread::getSec()
{
    return QDateTime::currentSecsSinceEpoch();
}

bool PlanThread::mapCurTime( PlanTime &_pt)
{
    QDateTime curTime = QDateTime::currentDateTime();

    if (_pt.myear>0&& curTime.date().year() != _pt.myear) {
        _pt.flag = false;
        return false;
    }
    if (_pt.mmon > 0 && curTime.date().month() != _pt.mmon) {
        _pt.flag = false;
        return false;
    }
    if (_pt.mday > 0 && curTime.date().day() != _pt.mday) {
        _pt.flag = false;
        return false;
    }
    if (_pt.mhour > 0 && curTime.time().hour() != _pt.mhour) {
        _pt.flag = false;
        return false;
    }
    if (_pt.mmin > 0 && curTime.time().minute() != _pt.mmin) {
        _pt.flag = false;
        return false;
    }
    int wdayVal = 0x01;
    if (_pt.wday > 0 && !((wdayVal << curTime.date().dayOfWeek()) & _pt.wday)) {
        _pt.flag = false;
        return false;
    }
    if (_pt.flag == false)
    {
        _pt.flag = true;
        return true;
    }
    else {
        return false;
    }
};

bool PlanThread::inWorkTime(unsigned int min_, QList<TVProperty> timeVS)
{
    if (timeVS.empty()) {
        return true;
    }
    for (int i = 0; i < timeVS.size(); i++)
    {
        if (timeVS.at(i).allStartMin < timeVS.at(i).allEndMin) {
            if (min_ >= timeVS.at(i).allStartMin&&min_ < timeVS.at(i).allEndMin)
            {
                return true;
            }
        }
        else {
            if (min_ >= timeVS.at(i).allStartMin || min_ < timeVS.at(i).allEndMin)
            {
                return true;
            }
        }
    }
    return false;
};

bool PlanThread::mapSleepTime(QList<TVProperty> timeVS,PlanSleep &_ps)
{
    QDateTime curTime = QDateTime::currentDateTime();
    unsigned int min_ = 60*curTime.time().hour()+curTime.time().minute();
    bool tt_in_work = inWorkTime(min_,timeVS);
    if (!tt_in_work)
        return false;
    //
    unsigned int _t = static_cast<unsigned int>(this->getSec());
    if (_ps.tt<_t)
    {
        _ps.tt = (unsigned int)_t + _ps.interval;
        return true;
    }
    return false;
};

bool PlanThread::conditionJude(QList<TVProperty> timeVS,QList<PlanCondition> _plancons)
{
    QDateTime curTime = QDateTime::currentDateTime();
    unsigned int min_ = 60*curTime.time().hour()+curTime.time().minute();
    bool tt_in_work = inWorkTime(min_,timeVS);
    if (!tt_in_work)
        return false;
    //
    bool _condition = true;//所有值是否满足条件
    bool ishasChange = false;//其中是否有变化值
    for (QList<PlanCondition>::iterator itc = _plancons.begin();
        itc != _plancons.end(); itc++)
    {
        float _val = 0.0;
        bool _valChange = false;
        //正确取回值,并该值被标记为变化
        if (mycdata->getConditionJude(itc->devID, itc->pID, itc->val, _val, _valChange))
        {
            if (_valChange)
                ishasChange = true;
            //判定值是否满足要求
            if (!compareVal(_val, itc->val, itc->compare))
            {
                _condition = false;
                break;
            }
        }
        else {
            _condition = false;
            break;
        }
    }
    return (_condition&&ishasChange);
};

bool PlanThread::compareVal(float _fv, float _tv, CompareType _ct)
{
    bool ret = false;
    switch (_ct)
    {
    case OnEqual:
        ret = (_fv == _tv);
        break;
    case OnMore:
        ret = (_fv < _tv);
        break;
    case OnLess:
        ret = (_fv > _tv);
        break;
    case ComTDef:
        ret = true;
        break;
    default:
        break;
    }
    return ret;
};

void PlanThread::doCmd(QList<PlanCMD> planCmds)
{
    for (QList<PlanCMD>::iterator it = planCmds.begin();
        it != planCmds.end(); it++)
    {
        PFromDev _pfrom;
        if (mycdata->getFromInfo(it->devID,it->pID,_pfrom))
        {
            if (it->timedelay > 0) {
                qint64 _usec = this->getUsec();
                WDSPCS wd(_pfrom.ipLong, it->exeType, _pfrom.pID, _pfrom.pType, it->val
                    , _usec+ static_cast<qint64>(it->timedelay),it->desc);
                m_MutexWDS.lock();
                WriteDataS.push_back(wd);
                m_MutexWDS.unlock();
            }
            else {
                RDS rds(it->exeType,it->pID,it->pType,it->val);
                m_ReceiveData->addRDS(rds);
                qInfo() << QString("plan cmd(%1),time(%2),ip(%3,%4),pID(%5),pType(%6),val(%7)")
                            .arg(it->desc)
                            .arg(PFunc::getCurrentTime())
                            .arg(_pfrom.ipLong).arg(_pfrom.ipStr)
                            .arg(_pfrom.pID).arg((int)_pfrom.pType).arg(it->val,0,'f',2);
                if (it->waitT>0) {
                    this->msleep(1000*(it->waitT));
                }
            }
        }
    }
};

